package com.tools.cleanmaster.controller;

import android.content.Context;
import android.os.Build;

import com.tools.cleanmaster.CleanConstant;
import com.tools.cleanmaster.model.TrashType;
import com.tools.cleanmaster.model.TrashesData;
import com.tools.cleanmaster.model.db.TrashDB;
import com.tools.cleanmaster.model.item.TrashItem;
import com.tools.cleanmaster.store.GlobalConfigSharedPrefManager;
import com.tools.cleanmaster.utils.FeatureConfig;
import com.tools.cleanmaster.utils.LogHelper;
import com.tools.cleanmaster.utils.TrashUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Created by lianzhan on 15/12/23.
 */
public class TrashQuickHandler extends TrashHandler {
    private static final String TAG = "TrashQuickHandler";

    private static final String THREAD_NAME_CLEAN = "TrashClean";

    /**
     * 为true时表示单核机器使用双线程扫描，false:单核机器不使用双线程
     */
    private static final boolean IS_SINGLE_CORE_TWO_THREAD = true;

    private TrashesData mTrashesData;

    private int mTypesScannedCount;

    private List<TrashScanner> mScanners;

    private List<ITrashScanListener> mScanListeners = new ArrayList<ITrashScanListener>();

    private boolean mIsCleanning = false;

    private HashMap<TrashScanner, Integer> mScannerTypeNumMap = new HashMap<TrashScanner, Integer>();

    private HashMap<TrashScanner, Integer> mScannerProgressMap = new HashMap<TrashScanner, Integer>();

    private boolean mIsBackScan = false;

    public TrashQuickHandler(Context context, TrashType[] types, boolean isBackScan) {
        super(context, types);
        if (types == null || types.length == 0) {
            LogHelper.e(TAG, "TrashHandler parameter types is error!!!");
        }
        this.mIsBackScan = isBackScan;
    }

    @Override
    public TrashesData getTrashesData() {
        if (mTrashesData == null) {
            mTrashesData = new TrashesData();
        }
        return mTrashesData;
    }

    @Override
    public int getTrashTypesCount() {
        return mTypesScannedCount;
    }

    @Override
    protected List<ITrashScanListener> getScanListeners() {
        return mScanListeners;
    }

    /**
     * @return 要scanner的type数
     */
    private int prepareScanners() {
        int totalTypeNum = 0;
        boolean hasSdCard = TrashUtils.hasSdcard(getRootDirs());
        mScanners = new ArrayList<TrashScanner>();
        TrashCacheAndResidualScanner mCacheAndResidualScanner = null;
        for (TrashType type : mTrashType) {
            if (type == TrashType.APP_CACHE) {
                TrashScanner scanner = new AppCacheScanner(mContext, this);
                mScanners.add(scanner);
                mScannerTypeNumMap.put(scanner, 1);
                totalTypeNum++;
            } else if (type == TrashType.APP_MEM) {
                TrashScanner mMemTrashScanner = new AppMemScanner(mContext, this);
                mScanners.add(mMemTrashScanner);
                mScannerTypeNumMap.put(mMemTrashScanner, 1);
                totalTypeNum++;
            } else if (type == TrashType.UNINSTALLED_APP || type == TrashType.APP_TRASH_FILE) {
                // 卸载残留和应用垃圾文件两类
                if (hasSdCard) {
                    if (mCacheAndResidualScanner == null) {
                        if (mIsBackScan) {
                            mCacheAndResidualScanner =
                                    new TraversalCacheAndResidualScanner(mContext, this, TrashDB.QUICK);
                        } else {
                            mCacheAndResidualScanner = new AppCacheAndResidualScanner(mContext, this);
                        }
                        mScanners.add(mCacheAndResidualScanner);
                        mScannerTypeNumMap.put(mCacheAndResidualScanner, 1);
                    } else {
                        mScannerTypeNumMap.put(mCacheAndResidualScanner,
                                mScannerTypeNumMap.get(mCacheAndResidualScanner) + 1);

                    }
                    totalTypeNum++;
                }
            } else if (type == TrashType.APK_FILE) {
                // 文件扫描
                if (hasSdCard) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                        FileMediaStoreScanner fileMediaStoreScanner = new ApkScanner(mContext, this);
                        mScanners.add(fileMediaStoreScanner);
                        mScannerTypeNumMap.put(fileMediaStoreScanner, 1);
                    } else {
                        FileRootScanner mFileScanner =
                                new FileRootScanner(mContext, this, new TrashType[] {TrashType.APK_FILE});
                        mScanners.add(mFileScanner);
                        mScannerTypeNumMap.put(mFileScanner, 1);
                    }
                    totalTypeNum++;
                }
            }
        }

        // 计算每个scanner对应的进度
        final int mProgressStep = 100 / totalTypeNum;
        final int size = mScanners.size();
        int progressTotal = 0;
        for (int i = 0; i < size; i++) {
            TrashScanner trashScanner = mScanners.get(i);
            if (i < size - 1) {
                int progress = mProgressStep * mScannerTypeNumMap.get(trashScanner);
                mScannerProgressMap.put(trashScanner, progress);
                progressTotal += progress;
            } else {
                mScannerProgressMap.put(trashScanner, 100 - progressTotal);
            }
        }

        return totalTypeNum;
    }

    @Override
    public void scan(ITrashScanListener listener) {
        mStopRequested = false;
        if (mScanListeners.contains(listener)) {
            return;
        }
        mScanListeners.add(listener);
        // 这里没有使用TrashesDataCache中的值，每次都真扫描
        new Thread(new Runnable() {
            @Override
            public void run() {
                doRealScan();
            }
        }).start();
    }

    private void doRealScan() {
        if (FeatureConfig.DEBUG_LOG) {
            LogHelper.i(TAG, "TrashScanHandler doScan begin");
        }
        onScanStart();
        mTypesScannedCount = prepareScanners();
        if (mTypesScannedCount > 0) {
            final int scannersSize = mScanners.size();
            final List<TrashScanner> notMmemCacheResidualScanners = new ArrayList<TrashScanner>();
            final List<TrashScanner> memCacheResuidualScanners = new ArrayList<TrashScanner>();
            for (int i = 0; i < scannersSize; i++) {
                final TrashScanner scanner = mScanners.get(i);
                if (IS_SINGLE_CORE_TWO_THREAD && CleanConstant.CPU_CORES == 1) {
                    if (!(scanner instanceof TrashCacheAndResidualScanner)
                            && !(scanner instanceof AppMemScanner)) {// 把非appMem和CacheAndResidual放一个线程中
                        notMmemCacheResidualScanners.add(scanner);
                    } else {
                        memCacheResuidualScanners.add(scanner);
                    }
                } else {
                    if (i < scannersSize - 1) {
                        new Thread(new Runnable() {

                            @Override
                            public void run() {
                                scanner.scan(mScannerProgressMap.get(scanner));

                            }
                        }).start();
                    } else {
                        scanner.scan(mScannerProgressMap.get(scanner));
                    }
                }
            }
            // 单核机器且使用双线程
            if (IS_SINGLE_CORE_TWO_THREAD && CleanConstant.CPU_CORES == 1) {
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        for (TrashScanner trashScanner : notMmemCacheResidualScanners) {
                            trashScanner.scan(mScannerProgressMap.get(trashScanner));
                        }
                    }
                }).start();
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        for (TrashScanner trashScanner : memCacheResuidualScanners) {
                            trashScanner.scan(mScannerProgressMap.get(trashScanner));
                        }
                    }
                }).start();
            }
        }
    }

    /**
     * 先在内存中同步的删除垃圾项，再实际的调用每一项的clean操作
     *
     * @param listener
     * @param items
     */
    public void clean(final ITrashCleanListener listener, final List<TrashItem> items) {
        // 先删除内存的数据，再异步执行删除操作
        if (isScanning()) {
            return;
        }
        if (listener != null) {
            listener.onCleanStart();
        }
        mIsCleanning = true;
        // 用来记录内存清理的包名
        List<String> memPkgs = new ArrayList<String>();
        for (TrashItem trashItem : items) {
            mTrashesData.removeTrashItem(trashItem);
            if (trashItem.trashType == TrashType.APP_MEM) {
                memPkgs.add(trashItem.pkgName);
            }
        }
        if (!memPkgs.isEmpty()) {
            GlobalConfigSharedPrefManager.setLastMemTrashCleanTime(mContext, System.currentTimeMillis());
            GlobalConfigSharedPrefManager.setLastMemTrashCleanPkgs(mContext, memPkgs);
        }
        // TODO:listener的onCleaned和onCleanFinish应该在哪个地方调用？
        // 是内存的删除时，还是实际的clean时？
        mIsCleanning = false;
        new Thread(new Runnable() {
            @Override
            public void run() {
                doClean(listener, items);
            }
        }, THREAD_NAME_CLEAN).start();
    }

    /**
     * 异步执行doClean
     *
     * @param listener
     * @param items
     */
    private void doClean(ITrashCleanListener listener, List<TrashItem> items) {
        boolean isAppSysCacheCleaned = false;
        for (TrashItem item : items) {
            // 删除系统缓存时，一次全部删除
            if (item.trashType == TrashType.APP_CACHE) {
                if (!isAppSysCacheCleaned) {
                    AppCacheScanner.clearAllAppCaches(mContext);
                    isAppSysCacheCleaned = true;
                }
            } else {
                item.clean();
            }
        }
    }

    /**
     * 如果正在扫描，则停止扫描
     *
     * @param notifyProgress
     */
    public void cancelScan(boolean notifyProgress) {
        if (FeatureConfig.DEBUG_LOG) {
            LogHelper.i(TAG, "cancel scan mStopRequested=" + mStopRequested + ",isScanning()="
                    + isScanning());
        }
        if (!isScanning()) {
            return;
        }
        mStopRequested = true;
        if (mScanners != null) {
            for (TrashScanner scanner : mScanners) {
                scanner.stop();
            }
        }
        if (notifyProgress) {
            onScanStop();
        }
    }

    public boolean isScanning() {
        if (mStopRequested) {
            return false;
        }
        if (mScanners != null) {
            for (TrashScanner scanner : mScanners) {
                if (scanner.isScanning()) {
                    return true;
                }
            }
        }
        return false;
    }

    public boolean isCleanning() {
        return !mStopRequested && mIsCleanning;
    }
}
